package org.softmed.rest.admin.aop.manager;

import java.util.ArrayList;
import java.util.List;
import org.softmed.action.Action;
import org.softmed.action.ActionStep;
import org.softmed.action.builder.ActionCreator;
import org.softmed.action.states.State;
import org.softmed.filehandling.FileUtil;
import org.softmed.rest.admin.aop.Aspect;
import org.softmed.rest.config.Handler;
import org.softmed.rest.server.core.handler.HandlerProcessParameters;

import com.google.inject.Inject;

public class AOPManager {

	@Inject
	ActionCreator actionCreator;

	List<Aspect> aspects = new ArrayList<Aspect>();

	FileUtil util = new FileUtil();

	public void addAspects(Action action, Handler handler,
			HandlerProcessParameters parameters) throws Throwable {
		List<Aspect> toBeApplied = getAspects(handler, parameters);

		for (Aspect aspect : toBeApplied) {
			applyAspect(aspect, action);
		}
	}

	private void applyAspect(Aspect aspect, Action action) throws Throwable {
		if (aspect.getAdvice().getBefore() != null) {
			String xml = getActionDescriptionXML(aspect.getAdvice().getBefore());
			Action before = actionCreator.getActionFromXML(xml);
			applyAspectAction(action, before, true);
		}

		if (aspect.getAdvice().getAfter() != null) {
			String xml = getActionDescriptionXML(aspect.getAdvice().getAfter());
			Action after = actionCreator.getActionFromXML(xml);
			applyAspectAction(action, after, false);
		}

		// xml = getActionDescriptionXML(aspect.getAspect().getAfter());
		// Action after = actionCreator.getActionFromXML(xml);
		//
		// applyAspectAction(action, after, false);

	}

	private String getActionDescriptionXML(String path) throws Throwable {
		String correctPath = path.replace('.', '/');
		correctPath = "/" + correctPath + ".xml";
		return util.readFromFile(correctPath);
	}

	private void applyAspectAction(Action action, Action before, boolean start) {
		applyState(action.getTest(), before.getTest(), start);
		applyState(action.getSetup(), before.getSetup(), start);
		applyState(action.getAsserting(), before.getAsserting(), start);
		applyState(action.getExecuting(), before.getExecuting(), start);

		applyState(action.getExecutionFailure(), before.getExecutionFailure(),
				start);
		applyState(action.getExecutionSuccess(), before.getExecutionSuccess(),
				start);
		applyState(action.getDisposing(), before.getDisposing(), start);
		applyState(action.getPreparationFailure(), before
				.getPreparationFailure(), start);
	}

	private void applyState(State action, State aspect, boolean start) {
		List<ActionStep> steps = aspect.getActionSteps();
		if (start)
			for (int i = steps.size() - 1; i >= 0; i--) {
				ActionStep step = steps.get(i);
				action.addStep(0, step);
			}
		else
			for (ActionStep actionStep : steps) {
				action.addStep(actionStep);
			}

	}

	public List<Aspect> getAspects(Handler handler,
			HandlerProcessParameters parameters) {
		List<Aspect> applicable = new ArrayList<Aspect>();

		for (Aspect aspect : aspects) {
			if (aspect.isApplicable(handler, parameters))
				applicable.add(aspect);
		}

		return applicable;

	}

	public List<Aspect> getAspects() {
		return aspects;
	}

	public void setAspects(List<Aspect> aspects) {
		this.aspects = aspects;
	}

}
